﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using AtletIS.Shared.Data;
using AtletIS.Shared.Data.aDbDataSetTableAdapters;
using AtletIS.Shared.Helpers;
using AtletIS.Shared.Entities;

namespace AtletIS.Shared.Forms
{
    public partial class frmAdvance : Form
    {
        private TreeNode tnDiscipline;
        private DisciplineListTableAdapter taDisciplineList = new DisciplineListTableAdapter();
        private PerformancesTableAdapter taPerformances = new PerformancesTableAdapter();
        private CompetitionsTableAdapter taCompetitors = new CompetitionsTableAdapter();

        #region Form

        public frmAdvance(TreeNode tnDiscipline)
        {
            InitializeComponent();

            this.tnDiscipline = tnDiscipline;
            this.Icon = Properties.Resources.AtletIS64;
        }

        private void frmAdvance_Load(object sender, EventArgs e)
        {
            lblTitle.Text += " " + tnDiscipline.Parent.Text;

            cmbPreviousRounds.DataSource = tnDiscipline.Parent.Nodes;
            cmbPreviousRounds.ValueMember = "Name";
            cmbPreviousRounds.DisplayMember = "Text";
            cmbPreviousRounds.SelectedIndex = -1;
            gbKey.Enabled = false;
        }

        #endregion

        #region Event handlers

        // Postupuju vsetci
        private void rbAll_CheckedChanged(object sender, EventArgs e)
        {
            nudHeatsCount.Enabled = !rbAll.Checked;
        }

        // Volba predchadzajuceho kola
        private void cmbPreviousRounds_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cmbPreviousRounds.SelectedItem == null)
                return;

            gbKey.Enabled = true;
        }

        // Postup
        private void tsbAdvance_Click(object sender, EventArgs e)
        {
            #region Kontrola

            if (cmbPreviousRounds.SelectedValue == null)
                return;

            string message = "Naozaj chcete vytvoriť ďalšie kolo: {0}" + Environment.NewLine + "Počet behov: {1} " + Environment.NewLine;

            if (rbTogether.Checked)
                message += "Najlepší pretekári: Spolu " + Environment.NewLine;
            if (rbSeparated.Checked)
                message += "Najlepší pretekári: Oddelene " + Environment.NewLine;
            if (rbBestInTotal.Checked)
                message += "Postupový kľúč: Najlepší v celkovom poradí";
            if (rbBestInHeats.Checked)
                message += "Postupový kľúč: Najlepší z každého behu({2}), doplnené podľa časov";

            message = string.Format(message, txtName.Text, nudHeatsCount.Value.ToString(), nudBestCount.Value.ToString());

            if (MessageBox.Show(message, "Postup", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                return;

            #endregion

            try
            {
                int prevRoundId = Convert.ToInt32(cmbPreviousRounds.SelectedValue);
                int totalCount = 0;

                #region Get performances

                aDbDataSet.PerformancesDataTable dtPerformances = null;

                // Pocet postupujucich
                if (this.rbNumberOfHeats.Checked)
                    totalCount = Convert.ToInt32(this.nudHeatsCount.Value * Globals.ActiveCompetition.LanesCount);
                else if (this.rbAll.Checked)
                    totalCount = int.MaxValue;

                // Nacita pretekarov
                if (rbBestInTotal.Checked)
                    dtPerformances = this.GetAllFromPreviousRound(prevRoundId);
                else if (rbBestInHeats.Checked)
                    dtPerformances = this.GetTopFromPreviousRound(prevRoundId, Convert.ToInt32(nudBestCount.Value), totalCount);

                if (dtPerformances == null || dtPerformances.Rows.Count == 0)
                    return;

                #endregion

                #region Sort and reset performances

                aDbDataSet.PerformancesDataTable dtNewPerformances = new aDbDataSet.PerformancesDataTable();
                
                var aPerformances = dtPerformances.Select("Code = 0 AND Result > 0", "Code, Result");
                int count = 0;
                foreach (DataRow dr in aPerformances)
                {
                    aDbDataSet.PerformancesRow drNew = dtNewPerformances.NewPerformancesRow();
                    this.NewPerformanceAdvanceRow(dr, ref drNew);
                    dtNewPerformances.AddPerformancesRow(drNew);

                    count += 1;

                    if (count >= totalCount)
                        break;
                }

                #endregion

                #region Vytvorenie disciplin

                aDbDataSet.DisciplineListDataTable dtPreviousRound = DatabaseHelper.GetDisciplineListById(prevRoundId);
                aDbDataSet.DisciplineListRow drPreviousRound = (aDbDataSet.DisciplineListRow)dtPreviousRound.Rows[0];

                #region Vytvori sub-disciplinu (level 2)

                aDbDataSet.DisciplineListRow drRoundHeader = dtPreviousRound.NewDisciplineListRow();

                DisciplineListHelper.CopyValues(drPreviousRound, ref drRoundHeader,
                    name: this.txtName.Text,
                    secondaryOrder: Convert.ToInt32(drPreviousRound["SecondaryOrder"]) + 1,
                    isFinal: this.chkFinal.Checked,
                    parentId: Convert.ToInt32(drPreviousRound["ParentId"]));

                drRoundHeader["DisciplineCode"] = drPreviousRound["DisciplineCode"];
                drRoundHeader["AutoOrder"] = DatabaseHelper.GetDisciplineListNewAutoOrder(Convert.ToInt32(drRoundHeader["CompetitionId"]));

                dtPreviousRound.AddDisciplineListRow(drRoundHeader);
                this.taDisciplineList.Update(dtPreviousRound);

                #endregion

                #region Vytvori cielove discipliny (level 3)

                aDbDataSet.DisciplineListDataTable dtChildDisciplines = DatabaseHelper.GetDisciplineListByParentIdActive(Convert.ToInt32(drRoundHeader["ID"]));
                
                int autoOrder = DatabaseHelper.GetDisciplineListNewAutoOrder(Convert.ToInt32(drRoundHeader["CompetitionId"]));

                for (int index = 1; index <= Convert.ToInt32(this.nudHeatsCount.Value); index++)
                {
                    aDbDataSet.DisciplineListRow drChildDiscipline = dtChildDisciplines.NewDisciplineListRow();

                    DisciplineListHelper.CopyValues(drRoundHeader, ref drChildDiscipline, name: string.Format("{0} {1}", this.txtName.Text, index), secondaryOrder: index, isFinal: this.chkFinal.Checked);
                    drChildDiscipline["DisciplineCode"] = drRoundHeader["DisciplineCode"];
                    drChildDiscipline["AutoOrder"] = autoOrder + index - 1;

                    dtChildDisciplines.AddDisciplineListRow(drChildDiscipline);
                }

                this.taDisciplineList.Update(dtChildDisciplines);

                #endregion

                #endregion

                #region Presun pretekarov (disciplina, draha)

                int splitCount = 0;

                if (this.rbTogether.Checked)
                {
                    foreach (DataRow drDiscList in dtChildDisciplines.Rows)
                    {
                        for (int i = 0; i < Globals.ActiveCompetition.LanesCount; i++)
                        {
                            if (splitCount + i >= dtNewPerformances.Rows.Count)
                                break;

                            dtNewPerformances.Rows[splitCount + i]["DisciplineListId"] = drDiscList["ID"];
                            dtNewPerformances.Rows[splitCount + i]["Lane"] = Convert.ToInt32(Globals.ActiveCompetition.LanesQuality[i]);
                        }
                        splitCount += Globals.ActiveCompetition.LanesCount;
                    }
                }

                if (this.rbSeparated.Checked)
                {
                    for (int i = 0; i < Globals.ActiveCompetition.LanesCount; i++)
                    {
                        for (int j = 0; j < dtChildDisciplines.Rows.Count; j++)
                        {
                            if (splitCount + j >= dtNewPerformances.Rows.Count)
                                break;

                            dtNewPerformances.Rows[splitCount + j]["DisciplineListId"] = dtChildDisciplines.Rows[j]["ID"];
                            dtNewPerformances.Rows[splitCount + j]["Lane"] = Convert.ToInt32(Globals.ActiveCompetition.LanesQuality[i]);
                        }
                        splitCount += dtChildDisciplines.Rows.Count;
                    }
                }

                this.taPerformances.Update(dtNewPerformances);

                #endregion

                MessageBox.Show("Postup prebehol úspešne!", "Postup", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace, "Postup", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Close();
            }
        }

        // Koniec 
        private void tsbClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion

        #region Private methods

        // Nacita vsetkych pretekarov z predosleho kola
        private aDbDataSet.PerformancesDataTable GetAllFromPreviousRound(int prevRoundId)
        {
            aDbDataSet.PerformancesDataTable dtPerformancesOut = DatabaseHelper.GetPerformancesByDisciplineListId(0);
            
            DataTable dtPrevDisciplineList = DatabaseHelper.GetDisciplineListByParentIdActive(prevRoundId);
            if (dtPrevDisciplineList != null && dtPrevDisciplineList.Rows.Count > 0)
            {
                foreach (DataRow dr in dtPrevDisciplineList.Rows)
                {
                    aDbDataSet.PerformancesDataTable dtPerformances = DatabaseHelper.GetPerformancesByDisciplineListId(Convert.ToInt32(dr["ID"]));
                    if (dtPerformances != null && dtPerformances.Rows.Count > 0)
                    {
                        foreach (aDbDataSet.PerformancesRow drPerformance in dtPerformances.Rows)
                        {
                            var newRow = dtPerformancesOut.NewPerformancesRow();
                            newRow.ItemArray = drPerformance.ItemArray.Clone() as object[];

                            dtPerformancesOut.AddPerformancesRow(newRow);
                        }
                    }
                }

                return dtPerformancesOut;
            }

            return null;
        }
        
        // Nacita najlepsich z kazdeho behu, doplni do celkoveho poctu
        private aDbDataSet.PerformancesDataTable GetTopFromPreviousRound(int prevRoundId, int topN, int totalCount)
        {
            aDbDataSet.DisciplineListDataTable dtPrevDisciplineList = DatabaseHelper.GetDisciplineListByParentIdActive(prevRoundId);
            if (dtPrevDisciplineList != null && dtPrevDisciplineList.Rows.Count > 0)
            {
                var dtTopPerformances = DatabaseHelper.GetPerformancesByDisciplineListId(0);
                var dtRestPerformances = DatabaseHelper.GetPerformancesByDisciplineListId(0);

                #region Fill top and rest

                // For each discipline in previous round
                foreach (DataRow drPrevRound in dtPrevDisciplineList.Rows)
                {
                    // Get performances
                    aDbDataSet.PerformancesDataTable dtPerfs = DatabaseHelper.GetPerformancesByDisciplineListId(Convert.ToInt32(drPrevRound["ID"])); 
                    if (dtPerfs != null && dtPerfs.Rows.Count > 0)
                    {
                        for (int i = 0; i < topN; i++)
                        {
                            // Fill top N to top table
                            var newRow = dtTopPerformances.NewPerformancesRow();
                            newRow.ItemArray = dtPerfs.Rows[i].ItemArray.Clone() as object[];

                            dtTopPerformances.AddPerformancesRow(newRow);
                        }

                        for (int i = topN; i < dtPerfs.Rows.Count; i++)
                        {
                            // Fill rest to rest table
                            var newRow = dtRestPerformances.NewPerformancesRow();
                            newRow.ItemArray = dtPerfs.Rows[i].ItemArray.Clone() as object[];

                            dtRestPerformances.AddPerformancesRow(newRow);
                        }
                    }
                }

                #endregion

                #region Add from rest to top

                // Top N table has less rows than total count
                int numberOfMissing = totalCount - dtTopPerformances.Rows.Count;
                var aRestPerformances = dtRestPerformances.Select(null, "Code, Result");
                for (int restIndex = 0; restIndex < numberOfMissing; restIndex++)
                {
                    // Fill rest to top table
                    var newRow = dtTopPerformances.NewPerformancesRow();
                    newRow.ItemArray = aRestPerformances[restIndex].ItemArray.Clone() as object[];

                    dtTopPerformances.AddPerformancesRow(newRow);
                }

                #endregion

                return dtTopPerformances;
            }

            return null;
        }

        // Resetne hodnoty zaznamu Performances
        private void NewPerformanceAdvanceRow(DataRow drFrom, ref aDbDataSet.PerformancesRow drTo)
        {
            drTo["DisciplineListId"] = Convert.ToInt32(drFrom["DisciplineListId"]);
            drTo["CompetitorId"] = Convert.ToInt32(drFrom["CompetitorId"]);
            drTo["FirstName"] = drFrom["FirstName"].ToString();
            drTo["Surname"] = drFrom["Surname"].ToString();
            drTo["BirthDate"] = Convert.ToDateTime(drFrom["BirthDate"]);
            drTo["Club"] = drFrom["Club"].ToString();
            drTo["CountryId"] = drFrom["CountryId"].ToString();
            drTo["SMS"] = string.Empty;
            drTo["StartNumber"] = Convert.ToInt32(drFrom["StartNumber"]);
            drTo["Lane"] = 0;
            drTo["Code"] = 0;
            drTo["SB"] = Convert.ToInt32(drFrom["SB"]);
            drTo["PB"] = Convert.ToInt32(drFrom["PB"]);
            drTo["Result"] = 0;
            drTo["ResultQuality"] = string.Empty;
            drTo["AdvResult"] = Convert.ToInt32(drFrom["Result"]);
            drTo["Rank"] = 0;
            drTo["SecondaryRank"] = 0;
            drTo["Reaction"] = string.Empty;
            drTo["Points"] = 0;
            drTo["PointsScoring"] = true;
            drTo["Active"] = true;
            drTo["Sync"] = false;
            drTo["WebId"] = 0;
            drTo["Modified"] = DateTime.Now;
        }

        #endregion

    }
}
